package com.lhkj.ct.meta.modules.psychology.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Maps;
import com.lhkj.ct.base.constants.Constants;
import com.lhkj.ct.base.model.dto.PageQuery;
import com.lhkj.ct.base.mybatis.core.metadata.SqlOrder;
import com.lhkj.ct.base.mybatis.extension.service.impl.BatchHandleServiceImpl;
import com.lhkj.ct.base.utils.ShiroUtil;
import com.lhkj.ct.base.utils.Validate;
import com.lhkj.ct.meta.modules.gauge.common.enums.GaugeType;
import com.lhkj.ct.meta.modules.gauge.mapper.GaugeQuestionMapper;
import com.lhkj.ct.meta.modules.gauge.mapper.ScaleMapper;
import com.lhkj.ct.meta.modules.gauge.mapper.ScaleSetMapper;
import com.lhkj.ct.meta.modules.gauge.model.entity.TblScale;
import com.lhkj.ct.meta.modules.patient.mapper.PatientMapper;
import com.lhkj.ct.meta.modules.psychology.mapper.PsyRecordMapper;
import com.lhkj.ct.meta.modules.psychology.mapper.ScaleReportMapper;
import com.lhkj.ct.meta.modules.psychology.model.bo.AllotRecordBo;
import com.lhkj.ct.meta.modules.psychology.model.dto.GaugeAllotDto;
import com.lhkj.ct.meta.modules.psychology.model.dto.ScanAllotDto;
import com.lhkj.ct.meta.modules.psychology.model.entity.TblScalePsyRecord;
import com.lhkj.ct.meta.modules.psychology.model.entity.TblScaleReport;
import com.lhkj.ct.meta.modules.psychology.model.vo.PsyRecordsVo;
import com.lhkj.ct.meta.modules.psychology.model.vo.ViewAnswerVo;
import com.lhkj.ct.meta.modules.psychology.service.PsyRecordService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *      描述
 * </p>
 *
 * @author job
 * @since 2023/10/15
 */
@Service
public class PsyRecordServiceImpl extends BatchHandleServiceImpl<PsyRecordMapper, TblScalePsyRecord> implements PsyRecordService {

    @Resource
    private PatientMapper patientMapper;

    @Resource
    private ScaleMapper scaleMapper;

    @Resource
    private GaugeQuestionMapper questionMapper;

    @Resource
    private ScaleReportMapper reportMapper;

    @Resource
    private ScaleSetMapper scaleSetMapper;

    @Override
    public boolean allot(GaugeAllotDto allotDto) {
        // 分配的量表
        final Set<String> scaleIds = allotDto.getScaleIds();
        if (CollectionUtils.isNotEmpty(allotDto.getScaleSets())) {
            scaleIds.addAll(scaleSetMapper.selectByCombs(allotDto.getScaleSets()));
        }
        Validate.notEmpty(scaleIds, "未查询到符合条件的量表，可能量表已删除或已禁用！");
        // 初始化档案id
        Set<String> patIds = new HashSet<>(allotDto.getPatIds());
        // 按标签
        if (CollectionUtil.isNotEmpty(allotDto.getPatLabelIds())) {
            patIds.addAll(patientMapper.selectUsersByLabels(allotDto.getPatLabelIds()));
        }
        // 按团体
        if (CollectionUtil.isNotEmpty(allotDto.getUnitIds())) {
            patIds.addAll(patientMapper.selectUsersByUnits(allotDto.getUnitIds()));
        }
        Validate.notEmpty(patIds, "未查询到符合条件的档案，可能档案已删除！");
        // 分配人
        final String createBy = ShiroUtil.getAuthUserInfo().getUserId();
        // 分配时间
        final LocalDateTime createTime = LocalDateTime.now();
        // 执行人
        final String executor = StringUtils.isNotBlank(allotDto.getExecutor()) ? allotDto.getExecutor() : ShiroUtil.getAuthUserInfo().getUserId();
        // 开单医生
        final String billDoctor = StringUtils.isNotBlank(allotDto.getBillDoctor()) ? allotDto.getBillDoctor() : ShiroUtil.getAuthUserInfo().getUserId();
        // 开单科室
        final String billDept = StringUtils.isNotBlank(allotDto.getBillDept()) ? allotDto.getBillDept() : ShiroUtil.getAuthUserInfo().getDeptId();
        // 开单时间
        final LocalDateTime billTime = Objects.nonNull(allotDto.getBillTime()) ? allotDto.getBillTime() : LocalDateTime.now();
        List<TblScalePsyRecord> psyRecords = patIds.stream()
                .map(p -> scaleIds.stream()
                        .map(s ->
                                TblScalePsyRecord
                                        .builder()
                                        .patId(p)
                                        .scaleId(s)
                                        .startTime(allotDto.getStartTime())
                                        .closingTime(allotDto.getClosingTime())
                                        .psyType(allotDto.getPsyType())
                                        .executor(executor)
                                        .billDoctor(billDoctor)
                                        .billDept(billDept)
                                        .billTime(billTime)
                                        .createBy(createBy)
                                        .createTime(createTime)
                                        .build()
                        ).collect(Collectors.toList()))
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        return super.saveBatch(psyRecords);
    }

    @Override
    public IPage<PsyRecordsVo> selectPages(PsyRecordsVo psyRecord, PageQuery pageQuery) {
        return getBaseMapper().selectPages(generatePage(pageQuery, SqlOrder.desc(TblScalePsyRecord::getCreateTime)), psyRecord, pageQuery);
    }

    @Override
    public IPage<PsyRecordsVo> selectPagesByPatient(PsyRecordsVo psyRecord, PageQuery pageQuery) {
        psyRecord.setPatId(ShiroUtil.getAuthUserInfo().getUserId());
        return getBaseMapper().selectPagesByPatient(generatePage(pageQuery, SqlOrder.desc(TblScalePsyRecord::getCreateTime)), psyRecord, pageQuery);
    }

    @Override
    public Map<String, Object> selectScaleWithQuestionsByAllotId(String allotId, boolean validateSelf) {
        final AllotRecordBo allotRecord = getBaseMapper().selectRecordWithRid(allotId);
        // 判断记录是否撤销
        Validate.isFalse(allotRecord == null, "记录已撤销，无法作答");
        // 判断是否已作答
        Validate.validState(null == allotRecord.getReportStatus() || allotRecord.getReportStatus() == -1, "测验已完成，不可再次作答");
        // 判断如果是用户，是否本人
        Validate.isFalse(validateSelf && (!allotRecord.getPatId().equals(ShiroUtil.getAuthUserInfo().getUserId())), "非本人无法作答");
        // 判断是否已开始
        Validate.isFalse(Objects.nonNull(allotRecord.getStartTime()) && allotRecord.getStartTime().after(new Date()),
                "测验暂未开始,[%tF %tT]后可作答", allotRecord.getStartTime(), allotRecord.getStartTime());
        // 判断是否超过截止时间
        Validate.isFalse(Objects.nonNull(allotRecord.getClosingTime()) && new Date().after(allotRecord.getClosingTime()),
                "测验已结束，不可作答");
        final TblScale scale = scaleMapper.selectOne(new LambdaQueryWrapper<TblScale>()
                .select(TblScale::getId, TblScale::getScaleName, TblScale::getInstruction, TblScale::getStatus)
                .eq(TblScale::getId, allotRecord.getScaleId()));
        // 判断量表是否存在
        Validate.isFalse(null == scale, "量表不存在，无法继续作答");
        // 判断量表是否禁用
//        Validate.validState(GlobalStatus.NORMAL.equals(scale.getStatus()), "量表已禁用，请联系管理员");
        Map<String, Object> resMap = Maps.newHashMap();
        if (null == allotRecord.getReportStatus()) {
            TblScaleReport scaleReport = new TblScaleReport();
            scaleReport.setAllotId(allotId);
            scaleReport.setScaleId(allotRecord.getScaleId());
            scaleReport.setPatId(allotRecord.getPatId());
            scaleReport.setPatName(allotRecord.getPatName());
            scaleReport.setPatSex(allotRecord.getPatSex());
            scaleReport.setPatAge(allotRecord.getPatAge());
            scaleReport.setPatBirthday(allotRecord.getPatBirthday());
            scaleReport.setPatMobile(allotRecord.getPatMobile());
            scaleReport.setReportStatus(-1);
            scaleReport.setStartTime(LocalDateTime.now());
            reportMapper.insert(scaleReport);
            allotRecord.setReportId(scaleReport.getId());
        }
        resMap.put("rId", allotRecord.getReportId());
        resMap.put("info", scale);
        resMap.put("questions", questionMapper.selectQutWithOptWithLogicByGaugeId(allotRecord.getScaleId(), GaugeType.SCALE));
        resMap.put("costTime", allotRecord.getCostTime());
        resMap.put("answerJson", allotRecord.getAnswerJson());
        return resMap;
    }

    @Override
    public ViewAnswerVo viewAnswer(String allotId) {
        final ViewAnswerVo answerVo = getBaseMapper().viewAnswer(allotId);
        // 判断记录是否撤销
        Validate.isFalse(answerVo == null ||
                answerVo.getReportStatus() == null || answerVo.getReportStatus() == -1, "未作答完成,无法查看！");
        return answerVo;
    }

    @Override
    public List<Map<String, Object>> countGroupByDate(LocalDate start, LocalDate end) {
        return getBaseMapper().countGroupByDate(start, end);
    }

    @Override
    public void scanAllot(ScanAllotDto scanAllotDto, HttpServletResponse response) throws IOException {
        Validate.isFalse(StringUtils.isBlank(scanAllotDto.getScaleId()) && StringUtils.isBlank(scanAllotDto.getSetId()), "分配参数缺少量表或组套参数");
        if (!ShiroUtil.getSubject().isAuthenticated()) {
            UriComponentsBuilder redirectBuilder = UriComponentsBuilder.fromUriString(Constants.SERVICE_BASE_URL).path("/service/api/iams/mp/authorize");
            String url = redirectBuilder.build().toUriString();
            response.sendRedirect(url);
//            response.setContentType("application/json;charset=UTF-8");
//            response.getWriter().write(JSON.toJSONString(ActionResult.fail(ReturnStatus.NO_LOGIN)));
            return;
        }
        String patId = ShiroUtil.getAuthUserInfo().getUserId();
        if (StringUtils.isNotBlank(scanAllotDto.getScaleId())) {
            TblScalePsyRecord build = TblScalePsyRecord
                    .builder()
                    .patId(patId)
                    .scaleId(scanAllotDto.getScaleId())
                    .psyType(2)
                    .executor(scanAllotDto.getDoctorId())
                    .billDoctor(scanAllotDto.getDoctorId())
                    .billDept(scanAllotDto.getDeptId())
                    .billTime(LocalDateTime.now())
                    .createBy(scanAllotDto.getDoctorId())
                    .createTime(LocalDateTime.now())
                    .build();
            getBaseMapper().insert(build);
        }
        if (StringUtils.isNotBlank(scanAllotDto.getSetId())) {
            Set<String> scaleIds = scaleSetMapper.selectByCombs(Collections.singletonList(scanAllotDto.getSetId()));
            Validate.notEmpty(scaleIds, "分配参数缺少量表或组套参数");
            final LocalDateTime currentTime = LocalDateTime.now();
            List<TblScalePsyRecord> psyRecords = scaleIds.stream().map(m -> TblScalePsyRecord
                    .builder()
                    .patId(patId)
                    .scaleId(m)
                    .psyType(2)
                    .executor(scanAllotDto.getDoctorId())
                    .billDoctor(scanAllotDto.getDoctorId())
                    .billDept(scanAllotDto.getDoctorId())
                    .billTime(currentTime)
                    .createBy(scanAllotDto.getDoctorId())
                    .createTime(currentTime)
                    .build()).collect(Collectors.toList());
            super.saveBatch(psyRecords);
        }
        UriComponentsBuilder redirectBuilder = UriComponentsBuilder.fromUriString(Constants.SERVICE_BASE_URL).path("/wechat/#/");
        String url = redirectBuilder.build().toUriString();
        response.sendRedirect(url);
    }
}
